namespace designpatternsplusplus.decorator.Support
{
    #region

    using System;
    using System.Linq;
    using System.Runtime.Serialization;
    using DecoratorParticipants;
    using designpatternsplus.contracts;

    #endregion

    /// <summary>
    /// 
    /// </summary>
    public static class ProductFactsExtension
    {
        /// <summary>
        /// *************************
        /// KEY METHOD!
        /// This is the key method to allow extensibility
        /// around adding dynamic delegate
        /// based decorator
        /// *************************
        /// Chains all defined decorators.
        /// </summary>
        /// <returns></returns>
        public static IProductService ChainToProductItems
            (this IProductService productServiceIn)
        {
            foreach (var delegateUseable in ItemDelegateRepository.Functions)
                productServiceIn = new DelegateDecorator
                    (productServiceIn, delegateUseable);

            return productServiceIn;
        }

        /// <summary>
        /// Resolves the type of the product by.
        /// </summary>
        /// <param name="Abbreviation">The abbreviation.</param>
        /// <returns></returns>
        public static SellableItem GetFirstMatchingItemOfCategory
            (this ItemCategory Abbreviation)
        {
            var itemDetail =
                CoolCrapMarket.Get.ProductsCarried.Where(f => f.Type.Name == Abbreviation)
                    .FirstOrDefault();

            return new SellableItem(itemDetail);
        }


        /// <summary>
        /// Gets into the event/delegate engine to
        /// avoid multiple subscriptions  by the same
        /// instance
        /// </summary>
        /// <param name="existing">The existing.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static bool ObserverHooked<T>(this T existing, Delegate value)
            where T : ICloneable, ISerializable
        {
            if (!typeof (Delegate).IsAssignableFrom(typeof (T)))
                throw new InvalidOperationException("Invalid Type " + typeof (T).Name);

            var _delegate = existing as Delegate;

            if (_delegate != null)
                return Array.Exists
                    (_delegate.GetInvocationList(), delegateIn => delegateIn.Equals(value));

            throw new InvalidOperationException("The value used was not a delegate");
        }
    }
}